# include "data_struct.h"
# include "IO.h"
# include "vector"
# include "map"
# include "set"
# include "string"
# include "stdio.h"
using namespace std;

bool read_data_line(FILE * data_file, map<string,int> * feature_name_id, Instance *instance)
{
	
	char str[MAX_LINE];
	char tmp[MAX_LINE/5];
	int  tmp_p = 0;
	map<string,int>::iterator iter;
	int value;
	bool isLabel;
	if(NULL != fgets(str,MAX_LINE,data_file))
	{

		isLabel = true;
		
		for(int i = 0; str[i] != 0 && str[i] != '\n' && str[i] != '\r'; i++)
		{
			if(' ' == str[i]|| '\t' == str[i])
			{
				tmp[tmp_p++] = 0;
			
				if(tmp_p>1)	
				if(isLabel)
				{
					isLabel = false;
					tmp_p = 0;
				}
				else{
					string feature_name(tmp);
					iter = feature_name_id->find(feature_name);
					if(feature_name_id->end() != iter)
					{
						value = iter->second;	
						instance->feature.insert(value);
					}
					
					tmp_p = 0;
				}
				
			}
			else{
				tmp[tmp_p++] = str[i];
			}
			
		}
		
		tmp[tmp_p++] = 0;
		if(tmp_p >1 ){
		if(isLabel)
		{
			isLabel = false;
			tmp_p = 0;
		}
		else
		{
			string feature_name(tmp);
			iter = feature_name_id->find(feature_name);
			if(feature_name_id->end() != iter)
			{
				value = iter->second;	
				instance->feature.insert(value);
			}
		
			tmp_p = 0;
		}
		}
		
		return true;
	}
	else
	{
		return false;
	}
}

bool read_data(const char * data_file_name, map<string,int> * feature_name_id, vector<Instance> *instances)
{
	FILE * data_file = fopen(data_file_name,"r");
	if(NULL == data_file)
	{
		fprintf(stderr,"[ERROR] read_data:: unable to open data file[%s]\n",data_file_name);
		return false;
	}
	char str[MAX_LINE];
	char tmp[MAX_LINE/5];
	int  tmp_p = 0;
	map<string,int>::iterator iter;
	int value;
	bool isLabel;
	int num_instance = 0;
	while(NULL != fgets(str,MAX_LINE,data_file))
	{
		num_instance ++;
		if(num_instance %1000  == 0)
		{
			printf(".");
			fflush(stdout);
		}
		if(num_instance %100000 == 0 && num_instance != 0)
			printf("\nreaded %d instances\n",num_instance);

		isLabel = true;

		Instance ins;
		for(int i = 0; str[i] != 0 && str[i] != '\n' && str[i] != '\r'; i++)
		{
			if(' ' == str[i]|| '\t' == str[i])
			{
				tmp[tmp_p++] = 0;
				
				if(isLabel)
				{
					isLabel = false;
					ins.label = atoi(tmp);
					tmp_p = 0;
				}
				else{
					string feature_name(tmp);
					iter = feature_name_id->find(feature_name);
					if(feature_name_id->end() != iter)
					{
						value = iter->second;	
					}
					else
					{

						value = feature_name_id->size();
						(*feature_name_id)[feature_name] = value;
					}
					ins.feature.insert(value);
					
					tmp_p = 0;
				}
				
			}
			else{
				tmp[tmp_p++] = str[i];
			}
			
		}
		
		tmp[tmp_p++] = 0;
		if(tmp_p >1 ){
		if(isLabel)
		{
			isLabel = false;
			ins.label = atoi(tmp);
			tmp_p = 0;
		}
		else
		{
			string feature_name(tmp);
			iter = feature_name_id->find(feature_name);
			if(feature_name_id->end() != iter)
			{
				value = iter->second;	
			}
			else
			{
				value = feature_name_id->size();
				(*feature_name_id)[feature_name] = value;
			}
			ins.feature.insert(value);
		
			tmp_p = 0;
		}
		}
		
		instances->push_back(ins);
	}
	return true;	
}
bool write_model(const char * model_file_name, map<string,int> * feature_name_id, vector<double> * weight,double beta0)
{
	//open
	FILE * model_file = fopen(model_file_name,"w");
	if(NULL == model_file)
	{
		fprintf(stderr,"[ERROR] write_model::unable to open model file[%s]",model_file_name);
		return false;
	}
	
	//write feature_name
	string *name = new string[feature_name_id->size()];
	fprintf(model_file,"feature_name_id\n");
	fprintf(model_file,"%d\n",feature_name_id->size());
	for(map<string,int>::iterator iter1 = feature_name_id->begin();iter1 != feature_name_id->end(); iter1++)
	{
		name[iter1->second] = iter1->first;
	}
	for(int i = 0 ; i < feature_name_id->size(); i ++)
	{
		fprintf(model_file,"%s %d\n",name[i].c_str(),i);
	}

	//write weight
	fprintf(model_file,"weight\n");
	fprintf(model_file,"%d\n",weight->size());
	for(int i = 0 ; i < weight->size(); i ++)
	{
		fprintf(model_file,"%d %lf\n",i,(*weight)[i]);
	}
	
	//write beta0
	fprintf(model_file,"beta0\n");
	fprintf(model_file,"%lf\n",beta0);

	//close model file
	fclose(model_file);
	
	return true;
}

bool read_model(const char * model_file_name, map<string,int> * feature_name_id, vector<double> * weight,double * beta0)
{
	//open
	FILE * model_file = fopen(model_file_name,"r");
	if(NULL == model_file)
	{
		fprintf(stderr,"[ERROR] read_model::unable to open model file[%s]",model_file_name);
		return false;
	}

	char str[MAX_LINE];
	
	//read feature_name_id
	int feature_id;
	fscanf(model_file,"%s",str);//read "feature_name_id"
	int num_feature;
	fscanf(model_file,"%d",&num_feature);
	for(int i = 0 ; i < num_feature; i ++)
	{
		fscanf(model_file,"%s %d",str,&feature_id);
		string feature_name(str);
		(*feature_name_id)[feature_name] = feature_id;
	}

	//read weight
	if(0 != weight->size())
	{
		fprintf(stderr,"[WARING] read_model::weight vector isn't empty and will be cleared\n");
		weight->clear();
	} 
	int weight_id;
	double weight_value;
	fscanf(model_file,"%s",str);//read "weight"
        int num_weight;
	fscanf(model_file,"%d",&num_weight);
	for(int i= 0 ; i < num_weight; i++)
	{
		fscanf(model_file,"%d %lf",&weight_id,&weight_value);
		weight->push_back(weight_value);
	}
	
	//read beta0
	fscanf(model_file,"%s",str);
	fscanf(model_file,"%lf",beta0);

	//close
	fclose(model_file);
	return true;
}
#ifdef IO_debug
int main()
{
	char data_file[1024]="head.data";
	printf("test_read_data\n");
	map<string,int> *feature_name_id= new map<string,int>();
	vector<Instance> *ins = new vector<Instance>();
	if(!read_data(data_file,feature_name_id,ins))
		return -1;
	printf("show feature_name_id\n");
	for(map<string,int>::iterator iter = feature_name_id->begin(); iter != feature_name_id->end(); iter++)
	{
		printf("%s %d\n",iter->first.data(),iter->second);
	}
	printf("show data\n");
	for(int i = 0 ; i < ins->size(); i++)
	{
		Instance e = (*ins)[i];
		printf("%d ",e.label);
		for(set<int>::iterator iter = e.feature.begin(); iter != e.feature.end(); iter++)
		{
			printf("%d ",*iter);
		}
		printf("\n");
	}	
	
	
	printf("\n\ntest_write_model\n");
	vector<double> * weight = new vector<double>();
	weight->push_back(0.56);
	weight->push_back(0.963);
	weight->push_back(0.778);
	write_model("model",feature_name_id,weight,0);
	

	double beta0;
	printf("\n\ntest_read_model\n");
	map<string,int> * new_feature_name_id = new map<string,int>();
	vector<double> * new_weight = new vector<double>();
	read_model("model",new_feature_name_id,new_weight,&beta0);
	printf("show feature_name_id\n");
	for(map<string,int>::iterator iter = new_feature_name_id->begin(); iter != new_feature_name_id->end(); iter++)
	{
		printf("%s %d\n",iter->first.data(),iter->second);
	}
	printf("show weight\n");
	for(int i = 0 ; i < new_weight->size();i++)
	{
		printf("%d %lf\n",i,(*new_weight)[i]);
	}
	
	printf("\n\ntest_read_data_line\n");
	FILE *file = fopen(data_file,"r");
	Instance inst;
	while(read_data_line(file,new_feature_name_id,&inst)){
		printf("show data\n");
		for(set<int>::iterator iter = inst.feature.begin(); iter != inst.feature.end(); iter++)
		{
			printf("%d,",*iter);
		}
		inst.feature.clear();
		printf("\n");
	}
	
}
#endif
